///
/// ArmyBodger 3
/// (c)2010 richyp
///
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ArmyBodger.Core {
    /// <summary>
    /// Represents a unit belonging to an Entry object
    /// </summary>
    public class Unit {
        /// <summary>
        /// Default Constructor
        /// </summary>
        public Unit() {
            this.Entry = null;
            this.Equipment = new EquipmentOptionCollection();
            this.Archetypes = new Dictionary<string, EquipmentOptionCollection>();
            this.Minimum = 0;
            this.Maximum = 0;
            this.InitialQuantity = 0;
            this.IsPrimary = false;
        }
        /// <summary>
        /// The entry this unit belings to
        /// </summary>
        public Entry Entry { get; set; }
        /// <summary>
        /// The name of this unit
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// The base entry the unit gets its attributes from
        /// </summary>
        public BaseUnit BaseUnit { get; set; }
        /// <summary>
        /// The raw cost of the unit sans upgrades and equipment
        /// </summary>
        public int BaseCost { get; set; }
        /// <summary>
        /// Collection of all possible EquipmentOptions available to 
        /// this unit
        /// </summary>
        public EquipmentOptionCollection Equipment { get; set; }
        /// <summary>
        /// Collection of all possible EquipmentOptionCollections to switch between a units archetypes (power armor options, termi armor options, etc)
        /// </summary>
        public Dictionary<string,EquipmentOptionCollection> Archetypes { get; set; }
        /// <summary>
        /// The minimum number of this Unit allowed per Entry
        /// </summary>
        public int Minimum { get; set; }
        /// <summary>
        /// The maximum number of this Unit allowed per Entry
        /// </summary>
        public int Maximum { get; set; }
        /// <summary>
        /// The starting quantity of this Unit when an Entry is created
        /// Note: x copies of Unit are created where x is this value
        /// </summary>
        public int InitialQuantity { get; set; }
        /// <summary>
        /// Is this the Entry objects primary unit, if so the +/- buttons
        /// on the list control will manipulate the quantities
        /// </summary>
        public bool IsPrimary { get; set; }
        /// <summary>
        /// Does this unit replace anther one in the same entry, e.g.
        /// Standard Bearer, Champion etc.. all replace a basic troop choice
        /// </summary>
        public string Replaces { get; set; }
        /// <summary>
        /// The total cost of this Unit, including any equipped EquipmentOption 
        /// objects
        /// </summary>
        public int Cost {
            get {
                int cost = this.BaseCost;
                foreach (EquipmentOption option in Equipment) {
                    if (option.Equipped ) {
                        cost += option.Cost;
                    } else if (option.Replacement != null) {
                        cost += option.Replacement.Cost;
                    }
                }

                //holy crap nesting
                if (Entry != null)
                {
                    foreach (Upgrade upgrade in Entry.Upgrades)
                    {
                        if (!upgrade.Applied)
                            continue;

                        foreach (KeyValuePair<string, EquipmentOptionCollection> kvp in this.Archetypes)
                        {
                            if (kvp.Key == upgrade.Name)
                            {
                                foreach (EquipmentOption option in kvp.Value)
                                {
                                    if (option.Equipped)
                                    {
                                        cost += option.Cost;
                                    }
                                    else if (option.Replacement != null)
                                    {
                                        cost += option.Replacement.Cost;
                                    }
                                }
                            }
                        }
                    }
                }
                return cost;
            }
        }
        /// <summary>
        /// Can another unit of this type be added to the parent Entry
        /// </summary>
        /// <param name="entry">The Entry this unit type belongs to</param>
        /// <returns>True if the addition of another unit of this type is possible</returns>
        public bool IsAddPermitted(Entry entry) {
            if (entry.Units.GetUnitsByName(this.Name).Count >= this.Maximum) {
                return false;
            }
            return true;
        }
        /// <summary>
        /// Can a unit of this type be removed from the parent Entry
        /// </summary>
        /// <param name="entry">The Entry this unit type belongs to</param>
        /// <returns>True if removal is possible</returns>
        public bool IsRemovePermitted(Entry entry) {
            if (entry.Units.GetUnitsByName(this.Name).Count >= this.Minimum) {
                return true;
            }
            return false;
        }
        /// <summary>
        /// Create a copy of this Unit instance
        /// </summary>
        /// <returns>A new instance of Unit based on this one</returns>
        public Unit Copy(Entry entry) {
            Unit newUnit = Unit.Copy(this);
            newUnit.Entry = entry;
            return newUnit;
        }
        /// <summary>
        /// Static Copy method that takes a Unit as a source instead of this instance
        /// </summary>
        /// <param name="source">The Unit object to Copy</param>
        /// <returns>A new instance of Unit cloned from the source version</returns>
        public static Unit Copy(Unit source) {
            Unit unit = new Unit();
            unit.Name = source.Name;
            unit.BaseUnit = source.BaseUnit;
            unit.BaseCost = source.BaseCost;
            unit.Equipment = new EquipmentOptionCollection();
            unit.Archetypes = source.Archetypes;
            unit.Replaces = source.Replaces;
            unit.IsPrimary = source.IsPrimary;
            foreach (EquipmentOption option in source.Equipment) {
                unit.Equipment.Add(option.Copy());
            }
            unit.Minimum = source.Minimum;
            unit.Maximum = source.Maximum;
            unit.InitialQuantity = source.InitialQuantity;
            return unit;
        }
        /// <summary>
        /// Unequip all EquipmentOption objects belonging to the specified category
        /// </summary>
        /// <param name="category">The category to unequip</param>
        public void RemoveAllByCategory(string category) {
            foreach (EquipmentOption option in this.Equipment) {
                if (option.Equipment.Category == category) {
                    option.Equipped = false;
                }
            }
        }
        /// <summary>
        /// Check if the named item/replacement item is equipped
        /// </summary>
        /// <param name="name">Name of the item to check</param>
        /// <returns>True or False if it's equipped or not</returns>
        public bool IsItemEquipped(string name) {
            bool equipped = false;
            foreach (EquipmentOption option in this.Equipment) {
                if (option.Equipment.Name == name && option.Equipped) {
                    equipped = true;
                    break;
                }
                if (option.HasReplacements) {
                    if (option.Replacement != null) {
                        if (option.Replacement.Equipment.Name == name) {
                            equipped = true;
                            break;
                        }
                    }
                }
            }
            return equipped;
        }
        /// <summary>
        /// Overriden to provide the name of the Unit
        /// </summary>
        /// <returns></returns>
        public override string ToString() {
            return this.Name;
        }
    }
}
